#include <iostream>
#include <fstream>
#include <filesystem>
#include <string>
#include <map>
#include <algorithm>
#include <cctype>
#include <cstdlib>

namespace fs = std::filesystem;

// 从PATH环境变量中查找编译器
std::string findCompilerInPath(const std::string& compilerName) {
    const char* pathEnv = std::getenv("PATH");
    if (!pathEnv) return compilerName;
    
    std::string pathStr(pathEnv);
    std::string delimiter;
    std::string pathSeparator;
    
#ifdef _WIN32
    delimiter = ";";
    pathSeparator = "\\";  // 用于文件系统查找
    std::string exeName = compilerName + ".exe";
#else
    delimiter = ":";
    pathSeparator = "/";
    std::string exeName = compilerName;
#endif
    
    size_t pos = 0;
    std::string token;
    while ((pos = pathStr.find(delimiter)) != std::string::npos) {
        token = pathStr.substr(0, pos);
        if (!token.empty()) {
            std::string fullPath = token + pathSeparator + exeName;
            if (fs::exists(fullPath)) {
                // 将反斜杠转换为正斜杠用于JSON输出
                std::replace(fullPath.begin(), fullPath.end(), '\\', '/');
                return fullPath;
            }
        }
        pathStr.erase(0, pos + delimiter.length());
    }
    
    // 检查最后一个路径
    if (!pathStr.empty()) {
        std::string fullPath = pathStr + pathSeparator + exeName;
        if (fs::exists(fullPath)) {
            // 将反斜杠转换为正斜杠用于JSON输出
            std::replace(fullPath.begin(), fullPath.end(), '\\', '/');
            return fullPath;
        }
    }
    
    return compilerName; // 如果找不到，返回原始名称
}

class VSCodeCppProjectGenerator {
private:
    std::string projectName;
    std::string cppStandard;
    std::string compiler;
    std::string projectPath;

public:
    VSCodeCppProjectGenerator(const std::string& name, const std::string& standard, const std::string& comp, const std::string& path)
        : projectName(name), cppStandard(standard), compiler(comp), projectPath(path) {}

    void generateProject() {
        try {
            createDirectoryStructure();
            generateCMakeFile();
            generateMainCpp();
            generateVSCodeConfig();
            generateGitIgnore();
            std::cout << "项目 '" << projectName << "' 创建成功！\n";
            std::cout << "项目路径: " << fs::absolute(projectPath) << "\n";
        } catch (const std::exception& e) {
            std::cerr << "创建项目失败: " << e.what() << "\n";
        }
    }

private:
    void createDirectoryStructure() {
        fs::create_directories(projectPath);
        fs::create_directories(projectPath + "/.vscode");
    }

    void generateCMakeFile() {
        std::ofstream file(projectPath + "/CMakeLists.txt");
        file << "cmake_minimum_required(VERSION 3.16)\n\n";
        file << "project(" << projectName << ")\n\n";
        file << "set(CMAKE_CXX_STANDARD " << cppStandard << ")\n";
        file << "set(CMAKE_CXX_STANDARD_REQUIRED ON)\n\n";
        file << "add_executable(${PROJECT_NAME}\n    main.cpp\n)\n";
    }

    void generateMainCpp() {
        std::ofstream file(projectPath + "/main.cpp");
        file << "#include <iostream>\n\n";
        file << "int main(int argc, char* argv[])\n{\n";
        file << "    std::cout << \"Hello from " << projectName << "!\" << std::endl;\n";
        file << "    return 0;\n";
        file << "}\n";
    }

    void generateVSCodeConfig() {
        generateTasksJson();
        generateLaunchJson();
    }

    void generateTasksJson() {
        std::ofstream file(projectPath + "/.vscode/tasks.json");
        
        // 从PATH环境变量中查找编译器的绝对路径
        std::string cCompiler = compiler;
        std::string cxxCompiler = compiler;
        
        if (compiler == "clang++") {
            cCompiler = "clang";
        } else if (compiler == "g++") {
            cCompiler = "gcc";
        } else if (compiler == "cl") {
            cCompiler = "cl";
        }
        
        // 尝试从PATH中找到编译器的绝对路径
        std::string cxxCompilerPath = findCompilerInPath(cxxCompiler);
        std::string cCompilerPath = findCompilerInPath(cCompiler);
        
        file << "{\n";
        file << "    \"version\": \"2.0.0\",\n";
        file << "    \"tasks\": [\n";
        file << "        {\n";
        file << "            \"label\": \"Configure\",\n";
        file << "            \"type\": \"shell\",\n";
        file << "            \"command\": \"cmake\",\n";
        file << "            \"args\": [\n";
        file << "                \"-S${workspaceFolder}\",\n";
        file << "                \"-B${workspaceFolder}/build/\",\n";
        file << "                \"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON\",\n";
        file << "                \"-DCMAKE_BUILD_TYPE=Debug\",\n";
        
        // Windows下使用Ninja生成器以获得更好的兼容性
        if (compiler != "cl") {
            file << "                \"-GNinja\",\n";
        }
        
        file << "                \"-DCMAKE_C_COMPILER=" << cCompilerPath << "\",\n";
        file << "                \"-DCMAKE_CXX_COMPILER=" << cxxCompilerPath << "\"\n";
        file << "            ]\n";
        file << "        },\n";
        file << "        {\n";
        file << "            \"label\": \"Build\",\n";
        file << "            \"type\": \"shell\",\n";
        file << "            \"command\": \"cmake --build ${workspaceFolder}/build --parallel\",\n";
        file << "            \"dependsOn\": \"Configure\",\n";
        file << "            \"group\": {\n";
        file << "                \"kind\": \"build\",\n";
        file << "                \"isDefault\": true\n";
        file << "            }\n";
        file << "        }\n";
        file << "    ]\n";
        file << "}\n";
    }

    void generateLaunchJson() {
        std::ofstream file(projectPath + "/.vscode/launch.json");
        
        // 根据编译器选择合适的调试器配置
        std::string debugger;
        std::string debuggerType;
        std::string debuggerPath;
        
        // 根据编译器选择调试器
        if (compiler == "cl") {
            debuggerType = "cppvsdbg";
        } else if (compiler.find("clang") != std::string::npos) {
            debuggerType = "lldb";  // 使用CodeLLDB扩展
            debugger = "lldb";
        } else {
            debuggerType = "cppdbg";
            debugger = "gdb";
            debuggerPath = findCompilerInPath("gdb");
        }
        
        file << "{\n";
        file << "    \"version\": \"0.2.0\",\n";
        file << "    \"configurations\": [\n";
        file << "        {\n";
        
        // 根据调试器类型设置不同的配置
        if (debuggerType == "lldb") {
            file << "            \"name\": \"CodeLLDB Debug\",\n";
            file << "            \"type\": \"lldb\",\n";
            file << "            \"request\": \"launch\",\n";
            file << "            \"program\": \"${workspaceFolder}/build/" << projectName;
#ifdef _WIN32
            file << ".exe";
#endif
            file << "\",\n";
            file << "            \"args\": [],\n";
            file << "            \"cwd\": \"${workspaceFolder}\",\n";
            file << "            \"console\": \"integratedTerminal\",\n";
            file << "            \"preLaunchTask\": \"Build\"\n";
        } else if (debuggerType == "cppvsdbg") {
            file << "            \"name\": \"MSVC Debug\",\n";
            file << "            \"type\": \"cppvsdbg\",\n";
            file << "            \"request\": \"launch\",\n";
            file << "            \"program\": \"${workspaceFolder}/build/" << projectName;
#ifdef _WIN32
            file << ".exe";
#endif
            file << "\",\n";
            file << "            \"args\": [],\n";
            file << "            \"stopAtEntry\": false,\n";
            file << "            \"cwd\": \"${workspaceFolder}\",\n";
            file << "            \"environment\": [],\n";
            file << "            \"console\": \"integratedTerminal\",\n";
            file << "            \"preLaunchTask\": \"Build\"\n";
        } else {
            // GDB配置
            file << "            \"name\": \"GDB Debug\",\n";
            file << "            \"type\": \"cppdbg\",\n";
            file << "            \"request\": \"launch\",\n";
            file << "            \"program\": \"${workspaceFolder}/build/" << projectName;
#ifdef _WIN32
            file << ".exe";
#endif
            file << "\",\n";
            file << "            \"args\": [],\n";
            file << "            \"stopAtEntry\": false,\n";
            file << "            \"cwd\": \"${workspaceFolder}\",\n";
            file << "            \"environment\": [],\n";
            file << "            \"externalConsole\": false,\n";
            file << "            \"MIMode\": \"gdb\",\n";
            file << "            \"miDebuggerPath\": \"" << debuggerPath << "\",\n";
            file << "            \"setupCommands\": [\n";
            file << "                {\n";
            file << "                    \"description\": \"Enable pretty-printing for gdb\",\n";
            file << "                    \"text\": \"-enable-pretty-printing\",\n";
            file << "                    \"ignoreFailures\": true\n";
            file << "                },\n";
            file << "                {\n";
            file << "                    \"description\": \"Set Disassembly Flavor to Intel\",\n";
            file << "                    \"text\": \"-gdb-set disassembly-flavor intel\",\n";
            file << "                    \"ignoreFailures\": true\n";
            file << "                }\n";
            file << "            ],\n";
            file << "            \"preLaunchTask\": \"Build\"\n";
        }
        
        file << "        }\n";
        file << "    ]\n";
        file << "}\n";
    }

    void generateGitIgnore() {
        std::ofstream file(projectPath + "/.gitignore");
        file << "# Build directories\n";
        file << "build/\n";
        file << "out/\n\n";
        file << "# VS Code settings (optional, comment if you want to share)\n";
        file << "# .vscode/\n\n";
        file << "# Executable files\n";
        file << "*.exe\n";
        file << "*.out\n";
        file << "*.app\n\n";
        file << "# Object files\n";
        file << "*.o\n";
        file << "*.obj\n\n";
        file << "# Debug files\n";
        file << "*.pdb\n";
        file << "*.ilk\n\n";
        file << "# CMake generated files\n";
        file << "CMakeCache.txt\n";
        file << "CMakeFiles/\n";
        file << "cmake_install.cmake\n";
        file << "compile_commands.json\n";
    }
};

void printUsage() {
    std::cout << "CppGen - C++ VS Code 项目模板生成器\n\n";
    std::cout << "使用方法:\n";
    std::cout << "  cppgen <项目名> [C++标准] [编译器] [项目路径]\n";
    std::cout << "  cppgen -n <项目名> [-s C++标准] [-c 编译器] [-p 项目路径]\n\n";
    std::cout << "选项参数:\n";
    std::cout << "  -n, --name <名称>      项目名称 (必填)\n";
    std::cout << "  -s, --standard <版本>  C++ 标准版本 (默认: 20, 支持: 11,14,17,20,23)\n";
    std::cout << "  -c, --compiler <编译器> 编译器名称 (默认: g++, 支持: g++,clang++,cl)\n";
    std::cout << "  -p, --path <路径>      项目创建路径 (默认: ./项目名)\n";
    std::cout << "  -h, --help             显示此帮助信息\n\n";
    std::cout << "位置参数示例:\n";
    std::cout << "  cppgen MyProject\n";
    std::cout << "  cppgen MyProject 17 g++\n\n";
    std::cout << "选项参数示例:\n";
    std::cout << "  cppgen -n MyProject\n";
    std::cout << "  cppgen -n MyProject -s 17 -c g++\n";
    std::cout << "  cppgen --name MyGame --standard 20 --compiler clang++\n";
}

struct ProjectConfig {
    std::string projectName;
    std::string cppStandard = "20";
    std::string compiler = "g++";
    std::string projectPath;
};

bool parseOptions(int argc, char* argv[], ProjectConfig& config) {
    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];
        
        if (arg == "-h" || arg == "--help") {
            return false;
        }
        else if (arg == "-n" || arg == "--name") {
            if (i + 1 < argc) {
                config.projectName = argv[++i];
            } else {
                std::cerr << "错误: " << arg << " 需要一个参数\n";
                return false;
            }
        }
        else if (arg == "-s" || arg == "--standard") {
            if (i + 1 < argc) {
                config.cppStandard = argv[++i];
            } else {
                std::cerr << "错误: " << arg << " 需要一个参数\n";
                return false;
            }
        }
        else if (arg == "-c" || arg == "--compiler") {
            if (i + 1 < argc) {
                config.compiler = argv[++i];
            } else {
                std::cerr << "错误: " << arg << " 需要一个参数\n";
                return false;
            }
        }
        else if (arg == "-p" || arg == "--path") {
            if (i + 1 < argc) {
                config.projectPath = argv[++i];
            } else {
                std::cerr << "错误: " << arg << " 需要一个参数\n";
                return false;
            }
        }
        else if (arg[0] == '-') {
            std::cerr << "错误: 未知选项 " << arg << "\n";
            return false;
        }
        else {
            // 位置参数
            if (config.projectName.empty()) {
                config.projectName = arg;
            } else if (config.cppStandard == "20") {
                config.cppStandard = arg;
            } else if (config.compiler == "g++") {
                config.compiler = arg;
            } else if (config.projectPath.empty()) {
                config.projectPath = arg;
            } else {
                std::cerr << "错误: 过多的参数 " << arg << "\n";
                return false;
            }
        }
    }
    
    if (config.projectName.empty()) {
        std::cerr << "错误: 必须指定项目名称\n";
        return false;
    }
    
    if (config.projectPath.empty()) {
        config.projectPath = "./" + config.projectName;
    }
    
    return true;
}

std::string normalizeCompiler(const std::string& compiler) {
    std::string normalized = compiler;
    
    // 转换为小写进行比较
    std::string lowerCompiler = compiler;
    std::transform(lowerCompiler.begin(), lowerCompiler.end(), lowerCompiler.begin(), ::tolower);
    
    if (lowerCompiler == "gcc") {
        normalized = "g++";
        std::cout << "警告: 检测到编译器 'gcc'，自动替换为 C++ 编译器 'g++'\n";
    } else if (lowerCompiler == "clang") {
        normalized = "clang++";
        std::cout << "警告: 检测到编译器 'clang'，自动替换为 C++ 编译器 'clang++'\n";
    }
    
#ifdef _WIN32
    // 在Windows下，提供编译器路径建议
    if (normalized == "clang++") {
        std::cout << "提示: 程序会从PATH环境变量中自动查找clang++的绝对路径\n";
        std::cout << "      以确保CMake正确识别编译器\n";
    } else if (normalized == "g++") {
        std::cout << "提示: 程序会从PATH环境变量中自动查找g++的绝对路径\n";
        std::cout << "      以确保CMake正确识别编译器\n";
    }
#endif
    
    return normalized;
}

int main(int argc, char* argv[])
{
    if (argc < 2) {
        printUsage();
        return 1;
    }

    ProjectConfig config;
    if (!parseOptions(argc, argv, config)) {
        printUsage();
        return 1;
    }

    // 规范化编译器名称
    config.compiler = normalizeCompiler(config.compiler);

    // 验证C++标准
    std::map<std::string, bool> validStandards = {
        {"98", true}, {"03", true}, {"11", true}, {"14", true}, 
        {"17", true}, {"20", true}, {"23", true}
    };
    
    if (validStandards.find(config.cppStandard) == validStandards.end()) {
        std::cerr << "错误: 不支持的C++标准 '" << config.cppStandard << "'\n";
        std::cerr << "支持的标准: 98, 03, 11, 14, 17, 20, 23\n";
        return 1;
    }

    std::cout << "正在创建C++ VS Code项目...\n";
    std::cout << "项目名称: " << config.projectName << "\n";
    std::cout << "C++标准: C++" << config.cppStandard << "\n";
    std::cout << "编译器: " << config.compiler << "\n";
    std::cout << "项目路径: " << config.projectPath << "\n\n";

    VSCodeCppProjectGenerator generator(config.projectName, config.cppStandard, config.compiler, config.projectPath);
    generator.generateProject();

    return 0;
}